/*
 * FNISVGEditor - JavaScript - based editor for SVG graphics 
 * Copyright (C) 2008 - 2009 Antti Leppä / Foyt
 * http://www.foyt.fi
 * 
 * License: 
 * 
 * Licensed under GNU Lesser General Public License Version 2.1 or later (the "LGPL") 
 * http://www.gnu.org/licenses/lgpl.html
 */
FNISVGEditorObjectEditPlugin = Class.create(FNISVGEditorPlugin, {
  initialize: function($super, editorInstance, pluginURL){
    $super(editorInstance, pluginURL);
    
    var button = new FNIToggleableButton({});
    button.domNode.addClassName('fniSVGEditor_ObjectEditPlugin_Button');
    button.setImage(this.getPluginURL() + "/gfx/icons/22x22/transformations/transform-move.png");
    button.addListener('buttonUp', this, this._onButtonUp);
    button.addListener('buttonDown', this, this._onButtonDown); 
    button.setTooltip(SVGLocale.getText("objectEditPlugin_buttonTooltip"));
    editorInstance.registerToolbarItem('editObject', button);   
  },
  getName: function(){
    return "objectedit";
  },
  setMode: function(mode){
    if (this._mode != mode) {
      this._lastMode = this._mode;
      this._mode = mode;
      
      switch (this._mode) {
        case FNISVGEditorObjectEditPlugin.MODE_SCALE:
          this.getEditorInstance().getSelectionManager().setIconset('scale');
          this.getEditorInstance().getSelectionManager().setMode(FNISelectionManager.MODE_SELECT);
        break;
        case FNISVGEditorObjectEditPlugin.MODE_ROTATE:
          this.getEditorInstance().getSelectionManager().setIconset('rotate');
          this.getEditorInstance().getSelectionManager().setMode(FNISelectionManager.MODE_SELECT);
        break;
        case FNISVGEditorObjectEditPlugin.MODE_NONE:
          this.getEditorInstance().getSelectionManager().setIconset('none');
          this.getEditorInstance().getSelectionManager().setMode(FNISelectionManager.MODE_SELECT);
        break;
        case FNISVGEditorObjectEditPlugin.MODE_MOVING:
          this.getEditorInstance().getSelectionManager().setIconset('none');
          this.getEditorInstance().getSelectionManager().setMode(FNISelectionManager.MODE_NONE);          
        break;
        case FNISVGEditorObjectEditPlugin.MODE_ROTATING:
          this.getEditorInstance().getSelectionManager().setIconset('none');
        break;        
      }
    }
  },
  getMode: function(){
    return this._mode;
  },
  setLastMode: function(){
    this.setMode(this._lastMode);
  },
  _onButtonUp: function(event){
    this._stopListening();
  },
  _onButtonDown: function(event){
    this._startListening();
    this._mode = undefined;
    this.setMode(FNISVGEditorObjectEditPlugin.MODE_SCALE);
  },
  _startListening: function(){
    this.getEditorInstance().addListener("mousedragstart", this, this._onEditorMouseDragStart);
    this.getEditorInstance().addListener("mousedragend", this, this._onEditorMouseDragEnd);
    this.getEditorInstance().addListener("mousedragging", this, this._onEditorMouseDragging);
    
    this.getEditorInstance().getSelectionManager().addListener("iconDragStart", this, this._onSelectionIconDragStart);
    this.getEditorInstance().getSelectionManager().addListener("iconDragging", this, this._onSelectionIconDragging);
    this.getEditorInstance().getSelectionManager().addListener("iconDragEnd", this, this._onSelectionIconDragEnd);
    this.getEditorInstance().getSelectionManager().addListener("mouseOverIcon", this, this._onMouseOverIcon);
    this.getEditorInstance().getSelectionManager().addListener("mouseOutIcon", this, this._onMouseOutIcon);
    this.getEditorInstance().getSelectionManager().addListener("mouseOutSelectedElement", this, this._onMouseOutSelectedElement);
    this.getEditorInstance().getSelectionManager().addListener("mouseOverSelectedElement", this, this._onMouseOverSelectedElement);
    this.getEditorInstance().getSelectionManager().addListener("selectedElementClick", this, this._onSelectedElementClick);
    this.getEditorInstance().getSelectionManager().addListener("selectionChanged", this, this._onSelectionChanged);
  },
  _stopListening: function(){
    this.getEditorInstance().removeListener("mousedragstart", this);
    this.getEditorInstance().removeListener("mousedragend", this);
    this.getEditorInstance().removeListener("mousedragging", this);
    
    this.getEditorInstance().getSelectionManager().removeListener("iconDragStart", this);
    this.getEditorInstance().getSelectionManager().removeListener("iconDragging", this);
    this.getEditorInstance().getSelectionManager().removeListener("iconDragEnd", this);
    this.getEditorInstance().getSelectionManager().removeListener("mouseOverIcon", this);
    this.getEditorInstance().getSelectionManager().removeListener("mouseOutIcon", this);
    this.getEditorInstance().getSelectionManager().removeListener("mouseOutElement", this);
    this.getEditorInstance().getSelectionManager().removeListener("mouseOverElement", this);
    this.getEditorInstance().getSelectionManager().removeListener("selectedElementClick", this);
    this.getEditorInstance().getSelectionManager().removeListener("selectionChanged", this);
  },
  _onSelectionIconDragStart: function(event){
    switch (this.getMode()) {
      case FNISVGEditorObjectEditPlugin.MODE_SCALE:
        this.setMode(FNISVGEditorObjectEditPlugin.MODE_SCALING);
        var undoGroup = new FNISVGEditorUndoableEventGroupEvent();
        
        var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
        for (var i = 0, len = elements.length; i < len; i++) {
          var element = elements[i];
          undoGroup.addEvent(new FNISVGEditorUndoableElementScaledEvent(element, fi.foyt.svg.svgdom.FNISVGDOMUtils.getScreenBBox(element)))
        }
        
        this.getEditorInstance().getUndoManager().addUndoableEvent(undoGroup);
      break;
      case FNISVGEditorObjectEditPlugin.MODE_ROTATE:
        this.setMode(FNISVGEditorObjectEditPlugin.MODE_ROTATING);
        this._currentAngle = 0;
        var selectionDimensions = this.getEditorInstance().getSelectionManager().getSelectionDimensions();
        this._rotOriginX = selectionDimensions.x + selectionDimensions.width / 2;
        this._rotOriginY = selectionDimensions.y + selectionDimensions.height / 2;        
      break;
    }
  },
  _onSelectionIconDragging: function(event){
    switch (this.getMode()) {
      case FNISVGEditorObjectEditPlugin.MODE_SCALING:
        var selectionManager = this.getEditorInstance().getSelectionManager();
        var selectionDimensions = selectionManager.getSelectionDimensions();
        
        var x = 0;
        var y = 0;
        var w = 0;
        var h = 0;
        
        if ((event.corner == FNISelectionManager.TOPLEFT_ICON) || (event.corner == FNISelectionManager.BOTTOMLEFT_ICON)) {
          x = event.mouseEditorX - selectionDimensions.x;
          w = (selectionDimensions.width / (selectionDimensions.width + x));
        }
        else {
          x = 0;
          w = event.mouseEditorX / (selectionDimensions.x + selectionDimensions.width);
        }
        
        if ((event.corner == FNISelectionManager.TOPLEFT_ICON) || (event.corner == FNISelectionManager.TOPRIGHT_ICON)) {
          y = event.mouseEditorY - selectionDimensions.y;
          h = (selectionDimensions.height / (selectionDimensions.height + y));
        }
        else {
          h = event.mouseEditorY / (selectionDimensions.y + selectionDimensions.height);
          y = 0;
        }
        
        var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
        if ((w > 0) && (h > 0)) {
          for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            var elementBo = fi.foyt.svg.svgdom.FNISVGDOMUtils.getScreenBBox(element);
            var controller = getSVGElementControllerVault().getElementControllerFor(element);
            
            var eX = selectionDimensions.x + ((elementBo.x - selectionDimensions.x) * w) + x;
            var eY = selectionDimensions.y + ((elementBo.y - selectionDimensions.y) * h) + y;
            controller.moveTo(element, eX, eY);
            controller.resizeBy(element, w, h);
            
            this.getEditorInstance().getSelectionManager().renderSelections();
          }
        }
        this.getEditorInstance().getSelectionManager().updateSelections();
      break;
      case FNISVGEditorObjectEditPlugin.MODE_ROTATING:
        var selectionManager = this.getEditorInstance().getSelectionManager();
        if (selectionManager.hasSelections() == true) {
          var selectionDimensions = selectionManager.getSelectionDimensions();
          var x1 = selectionDimensions.x + (selectionDimensions.width / 2);
          var y1 = selectionDimensions.y + (selectionDimensions.height / 2);
          var x2 = event.mouseEditorX;
          var y2 = event.mouseEditorY;
          var rAngle = this._getLineAngle(x1, y1, x2, y2);
          var dAngle = rAngle * 180 / Math.PI;
          var change = rAngle - this._currentAngle;
          var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
          for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            var elementBo = fi.foyt.svg.svgdom.FNISVGDOMUtils.getScreenBBox(element);
            var controller = getSVGElementControllerVault().getElementControllerFor(element);
            controller.rotateBy(element, change, this._rotOriginX, this._rotOriginY);
          }
          this._currentAngle = rAngle;
          this.getEditorInstance().getSelectionManager().updateSelections();
          this.getEditorInstance().getSelectionManager().renderSelections();
        }
      break;
    }
  },
  _onSelectionIconDragEnd: function(event){
    switch (this.getMode()) {
      case FNISVGEditorObjectEditPlugin.MODE_SCALING:
        this.setLastMode();
      break;
      case FNISVGEditorObjectEditPlugin.MODE_ROTATING:
        this.setLastMode();        
        
        var undoGroup = new FNISVGEditorUndoableEventGroupEvent();
        
        var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
        for (var i = 0, len = elements.length; i < len; i++) {
          var element = elements[i];
          undoGroup.addEvent(new FNISVGEditorUndoableElementRotatedEvent(element, this._currentAngle, this._rotOriginX, this._rotOriginY));
        }
        
        this.getEditorInstance().getUndoManager().addUndoableEvent(undoGroup);

        this._rotOriginX, this._rotOriginY, this._currentAngle = undefined;
      break;
    }
  },
  _onMouseOverIcon: function(event){
    switch (this.getMode()) {
      case FNISVGEditorObjectEditPlugin.MODE_SCALE:
        switch (event.corner) {
          case FNISelectionManager.TOPLEFT_ICON:
            this.getEditorInstance().changeCursor("nw-resize");
          break;
          case FNISelectionManager.TOPRIGHT_ICON:
            this.getEditorInstance().changeCursor("ne-resize");
          break;
          case FNISelectionManager.BOTTOMLEFT_ICON:
            this.getEditorInstance().changeCursor("sw-resize");
          break;
          case FNISelectionManager.BOTTOMRIGHT_ICON:
            this.getEditorInstance().changeCursor("se-resize");
          break;
        }
      break;
      case FNISVGEditorObjectEditPlugin.MODE_ROTATE:
        this.getEditorInstance().changeCursor("move"); 
      break;
    }
  },
  _onMouseOutIcon: function(event){
    this.getEditorInstance().resetCursor();
  },
  _onMouseOverSelectedElement: function(event){
    this.getEditorInstance().changeCursor("move");
  },
  _onMouseOutSelectedElement: function(event){
    this.getEditorInstance().resetCursor();
  },
  _onSelectedElementClick: function (event) {
    switch (this.getMode()) {
      case FNISVGEditorObjectEditPlugin.MODE_SCALE:
        if (this._selectedElementsSupport(fi.foyt.svg.svgdom.FNISVGElementController.OPERATION_ROTATE))
          this.setMode(FNISVGEditorObjectEditPlugin.MODE_ROTATE);
      break;
      case FNISVGEditorObjectEditPlugin.MODE_ROTATE:
        this.setMode(FNISVGEditorObjectEditPlugin.MODE_SCALE);
      break;        
    }
  },
  _onEditorMouseDragStart: function(event){
    switch (this._mode) {
      case FNISVGEditorObjectEditPlugin.MODE_ROTATE:
      case FNISVGEditorObjectEditPlugin.MODE_SCALE:
        var element = this.getEditorInstance().getSelectionManager().getSelectedElementAt(event.mouseEditorX, event.mouseEditorY);
        if (element != null) {
          this.setMode(FNISVGEditorObjectEditPlugin.MODE_MOVING);
          
          var undoGroup = new FNISVGEditorUndoableEventGroupEvent();
          
          var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
          for (var i = 0, len = elements.length; i < len; i++) {
            var element = elements[i];
            undoGroup.addEvent(new FNISVGEditorUndoableElementMovedEvent(element, fi.foyt.svg.svgdom.FNISVGDOMUtils.getScreenBBox(element)))
          }
          
          this._editorInstance.getUndoManager().addUndoableEvent(undoGroup);
        }
      break;
    }
  },
  _onEditorMouseDragEnd: function(event){
    switch (this._mode) {
      case FNISVGEditorObjectEditPlugin.MODE_MOVING:
        this.setLastMode();
      break;
    }
  },
  _onEditorMouseDragging: function(event){
    switch (this._mode) {
      case FNISVGEditorObjectEditPlugin.MODE_MOVING:
        var moveX = event.mouseEditorX - event.mouseLastX;
        var moveY = event.mouseEditorY - event.mouseLastY;
        
        var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
        
        for (var i = 0; i < elements.length; i++) {
          var element = elements[i];
          var elementBo = fi.foyt.svg.svgdom.FNISVGDOMUtils.getScreenBBox(element);
          var controller = getSVGElementControllerVault().getElementControllerFor(element);
          controller.moveBy(element, moveX, moveY);
        }
        
        this.getEditorInstance().getSelectionManager().updateSelections();       
      break;
    }
  },
  _getLineAngle: function(x1, y1, x2, y2){
    var angle = 0;
    var leg1 = (y1 - y2);
    var leg2 = (x2 - x1);
    
    if ((leg2 < 0) && (leg1 < 0)) {
      angle = Math.PI; // 180        
    }
    else if (leg1 < 0) {
      angle = Math.PI / 2; // 90
      var tmp = leg2;
      leg2 = leg1;
      leg1 = tmp;
    }
    else if (leg2 < 0) {
      angle = Math.PI * 1.5; // 270
      var tmp = leg2;
      leg2 = leg1;
      leg1 = tmp;
    }
    
    return angle + Math.atan(Math.abs(leg2) / Math.abs(leg1));
  },
  _onSelectionChanged: function (event) {
    this.setMode(FNISVGEditorObjectEditPlugin.MODE_SCALE);
  },
  _selectedElementsSupport: function(operation){
    var elements = this.getEditorInstance().getSelectionManager().getSelectedElements();
    for (var i = 0, len = elements.length; i < len; i++) {
      var controller = getSVGElementControllerVault().getElementControllerFor(elements[i]);
      if (!controller.supports(operation))
        return false;
    }
    
    return true;    
  }   
});

Object.extend(FNISVGEditorObjectEditPlugin, {
  MODE_NONE: 'none',
  MODE_MOVING: 'moving',
  MODE_SCALE: 'scale',
  MODE_SCALING: 'scaling',
  MODE_ROTATE: 'rotate',
  MODE_ROTATING: 'rotating'
});

Object.extend(FNISVGEditorObjectEditPlugin, {
  ICONS_NONE: 'none',
  ICONS_SCALE: 'scale',
  ICONS_ROTATE: 'rotate'
});


document.fire("svgEditorPluginLoaded:objectedit", {
  pluginClass: FNISVGEditorObjectEditPlugin
});
